#include <iostream>
#include <signal.h> //用sigaction
#include <unistd.h>
#include <cstdlib>
#include <sys/wait.h>

// void handler(int signum)
// {
//     std::cout<<"hello  signal: "<< signum <<std::endl;
//     while(true)
//     {
//         //不断获取pending表
//         sigset_t pending;
//         sigpending(&pending);
//         for(int i=31;i>=1;i--)
//         {
//             if(sigismember(&pending,i))        //sigismember 测试参数signum 代表的信号是否已加入至参数set信号集里
//                 std::cout<<"1";
//             else
//                 std::cout<<"0";
//         }
//         std::cout<<std::endl;
//         sleep(1);
//     }
//     exit(0);
// }
// //第一次进行对二号信号捕捉后  会进入信号捕捉状态  一直全0    再发送二号信号二号信号就会变为1

// int main()
// {
//     struct sigaction act,oact;     //创建两个sigaction的结构体
//     act.sa_handler = handler;

//     sigemptyset(&act.sa_mask);     //清空信号集

//     //想把信号 mask 3号4号也给进行捕捉   就把他们添加进来
//     sigaddset(&act.sa_mask,3);
//     sigaddset(&act.sa_mask,4);       //这就把对应的3号4号信号给添加进来了
//     //一旦添加进来之后，一旦把2号进行捕捉，就会连带把234号都给屏蔽

//     act.sa_flags = 0;     //把标志位 置为0  防止产生随机数

// //数据类型名字和函数名字可以是一样的sigaction    尽量不一样
//     sigaction(SIGINT,&act,&oact);       //测试对2号信号进行捕捉   参数二：自定义捕捉方法   参数三：老的sigaction   oldact

//     while(true)
//     {
//         std::cout<<"hello  world！ "<<getpid()<<std::endl;
//         sleep(1);
//     }

//     return  0;
// }

// 测试 子进程退出会给父进程发送17号信号
//  void Say(int num)
//  {
//      std::cout<<"father get a signal: "<< num << std::endl;
//  }

// int  main()
// {
//     //父进程
//     signal(SIGCHLD,Say);     //查看是否发送信号   子进程退出会给父进程发送17信号！   以前默认看不到，是因为默认忽略

//     pid_t id = fork();
//     if(id == 0)
//     {
//         std::cout<<"I am child,exit"<<std::endl;
//         sleep(3);
//         exit(3);
//     }

//     waitpid(id,nullptr,0);
//     std::cout<<"I am father,exit"<<std::endl;
// }




void WaitAll(int num)
{
    while (true)
    {
        pid_t n = waitpid(-1, nullptr, WNOHANG); // waitpid 这样不管是一个进程还是多个进程这样都会回收所有子进程，不会阻塞
        if (n == 0)                              // 使用WNOHANG
        {                                        // 对于waitpid(-1,nullptr,0) 一次只能回收一个，就会阻塞，主进程就不会继续
            break;                               // 对于waitpid(-1,nullptr,WNOHANG)   就不会影响主进程,等待回收
        }
        else if (n < 0)
        {
            std::cout << "waitpid error" << std::endl;
            break;
        }
    }
    std::cout << "father get a signal: " << num << std::endl;
}

int main()
{
    // 父进程
    signal(SIGCHLD, WaitAll); // 查看是否发送信号   子进程退出会给父进程发送17信号！   以前默认看不到，是因为默认忽略
    for (int i = 0; i < 10; i++)      //有着十个子进程    6个子进程退出，4个不退出
    {
        pid_t id = fork();
        if (id == 0)
        {
            sleep(3);
            std::cout << "I am child,exit" << std::endl;
            if(i<=6)  exit(3);
            else pause();        //余下的四个进入暂停   如果waitpid是waitpid(-1,nullptr,0);     就会一直阻塞在waitpid那
        }
    }
    while (true)
    {
        std::cout << "I am father,exit" << std::endl;
        sleep(1);
    }
    return 0;
}